
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数据编辑器</title>
  <style>
    .el-table .el-table__cell .el-input__inner {
      overflow: visible;
      white-space: normal;
    }
    .el-table .el-table__cell {
      overflow: visible;
    }
  </style>
  <link rel="stylesheet" href="static/css/index.css">
  <script type="text/javascript" src="static/js/vue.js"></script>
  <script type="text/javascript" src="static/js/vue-resource.min.js"></script>
  <script type="text/javascript" src="static/js/vue-router.min.js"></script>
  <script type="text/javascript" src="static/js/element-ui.js"></script>
  <script type="text/javascript" src="static/js/axios.min.js"></script>
  <script type="text/javascript" src="static/js/mock.js"></script>
  <!-- Papa Parse for CSV handling -->
  <script src="static/js/papaparse.min.js"></script>
  <!-- SheetJS for Excel parsing -->
<!--  <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>-->
  <script src="static/js/xlsx-full.min.js"></script>
</head>
<body >
<div id="app">
  <div style="display:flex;height:19vh;width: 99%; border: 1px solid #dcdfe6; border-radius: 4px; padding: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
  <div style="flex:1;">
      <el-upload
              class="upload-demo el-upload--drag flex-1"
              action="#"
              :auto-upload="false"
              :on-change="handleFileUpload"
              :show-file-list="false"
              accept=".csv, .dat, .xlsx"
              drag
              style="margin-right: 20px"
      >
        <div class="flex flex-col items-center justify-center p-2 h-full">
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        </div>
      </el-upload>
    </div>
    <div style="flex:4;display:flex;flex-direction:column">
      <div style="flex:1; display:flex">
        <div  style="flex:1; margin-right: 20px;">
           <el-input v-model="replaceRulesStr" placeholder="格式: name:王五,date:20250819,type:2" style="width: 100%;"
                  type="textarea" :rows="4"></el-input>
        </div>
        <div style="flex:2; display:flex; flex-direction:column">
          <div style="flex:1;">
            <el-button type="primary" @click="batchReplace" size="medium" >替换当前页</el-button>
            <el-button type="primary" @click="batchReplaceAll" size="medium">替换全部页</el-button>
          </div>
          <div  style="flex:1;">
            <el-button type="primary" @click="downloadCSV"  size="medium">下载当前页</el-button>
            <el-button type="primary" @click="downloadAllCSV" size="medium">下载所有页</el-button>
          </div>
           <!--        <el-button type="danger" @click="resetData" icon="el-icon-refresh" size="medium">重置</el-button>-->
        </div>
      </div>
      <div style="flex:1; display:flex; align-items:center">
        <div v-if="filesData.length > 0" style="display: flex; flex-wrap: wrap; gap: 8px;">
          <el-tag
                  v-for="(file, index) in filesData"
                  :key="index"
                  :type="index === activeFileIndex ? '' : 'info'"
                  @click="switchFile(index)"
                  closable
                  @close="deleteFile(index)"
                  style="margin-bottom: 5px;"
          >
            {{ file.name }}
          </el-tag>
        </div>
      </div>
    </div>
  </div>

  <!-- 数据表格区域：占屏幕80% -->
  <div v-if="csvData.length" style="height: 80vh;">
    <el-table
            v-loading="loading"
            :data="csvData"
            style="width: 100%;"
            height="100%"
            max-height="76vh"
            border
            fit
            highlight-current-row
    >
      <el-table-column
              type="index"
              width="50">
      </el-table-column>
      <!-- 动态生成表格列 -->
      <el-table-column
              v-for="col in headers || []"
              :key="col"
              :prop="col"
              :label="col"
              show-overflow-tooltip
              width="200"
      >
        <template slot-scope="{ row, column }">
          <el-input
                  v-model="row[column.property]"
                  size="small"
                  @change="updateCell(row._index, column.property, $event)"
                  :title="row[column.property]"
          />
        </template>
      </el-table-column>
    </el-table>
    <div v-if="csvData.length > 0 && !headers.length" class="mt-3 text-sm text-yellow-500">
      警告: 数据存在但无法确定列数，请检查CSV格式
    </div>
  </div>
</div>

<script>
  // 创建Vue实例
  const app = new Vue({
    el: '#app',
    // 组件数据
    data: {
      filesData: [], // 存储多个文件的数据
      activeFileIndex: -1, // 当前活动文件的索引
      loading: false, // 加载状态指示器
      replaceRulesStr: '', // 替换规则字符串，格式: name:王五,date:20250819,type:2
      excelHeaders: null, // 存储从Excel加载的表头信息
      tableHeaderLists: {}, // 存储以TABLE_HEAR_LIST格式命名的表头
      fileList: [] // 文件列表
    },
    computed: {
      // 当前活动文件的数据
      currentFileData() {
        if (this.activeFileIndex >= 0 && this.activeFileIndex < this.filesData.length) {
          return this.filesData[this.activeFileIndex];
        }
        return null;
      },
      // 当前文件的CSV数据
      csvData() {
        return this.currentFileData ? this.currentFileData.csvData : [];
      },
      // 当前文件的原始数据
      originalData() {
        return this.currentFileData ? this.currentFileData.originalData : [];
      },
      // 当前文件的表头
      headers() {
        return this.currentFileData ? this.currentFileData.headers : [];
      }
    },
    // 生命周期钩子：组件挂载后
    mounted() {
      console.log('应用已挂载到#app');
    },
    // 方法
    methods: {
      /**
       * 处理文件上传
       * @param {File} file - 上传的文件对象
       */
      handleFileUpload(file) {
        if (!file) return;

        this.loading = true;
        console.log('开始解析文件:', file.name);

        // 检查文件类型
        const fileName = file.name;
        const lastDotIndex = fileName.lastIndexOf('.');
        const hasExtension = lastDotIndex !== -1;
        const extension = hasExtension ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';

        // 处理Excel文件
        if (extension === 'xlsx') {
          if (fileName.includes('京东数科账务文件产品文档')) {
            this.readExcelFile(file);
          } else {
            this.loading = false;
            this.$message.error('请上传有效的京东数科账务文件产品文档');
            return;
          }
        } 
        // 处理CSV、DAT和无后缀名文件
        else if (!hasExtension || extension === 'csv' || extension === 'dat') {
          // 检查是否已上传Excel文档
          if (extension === 'dat' && !this.excelHeaders) {
            this.loading = false;
            this.$message.warning('请先上传京东数科账务文件产品文档-分分卡20240822.xlsx');
            return;
          }
          this.loadDataFile(file);
        } else {
          this.loading = false;
          this.$message.warning('仅支持CSV、DAT、Excel文件和无后缀名文件');
          return;
        }
      },

      /**
       * 加载数据文件(CSV/DAT)
       */
      loadDataFile(file) {
        const fileName = file.name;
        const isDAT = fileName.endsWith('.dat');
        const isCSV = fileName.endsWith('.csv');
        const isNoExtension = !fileName.includes('.');

        if (isDAT) {
          // 处理DAT文件 (GBK编码, @!@分隔, 无表头)
          const reader = new FileReader();
          reader.onload = (e) => {
            try {
              // 使用TextDecoder处理GBK编码
              const decoder = new TextDecoder('gbk');
              const content = decoder.decode(e.target.result);

              // 按@!@分隔符拆分数据
              const lines = content.split('\n');
              const data = [];

              // 查找匹配的表头 - 使用TABLE_HEAR_LIST格式
              let matchedHeaders = [];
              console.log('DAT文件名:', fileName);
              
              // 从文件名提取前缀（如"JD_CUS", "JD_PLAN"）
              // 匹配所有字符直到第一个数字前的下划线
              const fileNameMatch = fileName.match(/^([A-Za-z0-9_]+?)_(\d|\.dat)/);
              let filePrefix = '';
              
              if (fileNameMatch && fileNameMatch[1]) {
                filePrefix = fileNameMatch[1];
                console.log('从文件名提取的完整前缀:', filePrefix);
              } else {
                // 如果新的正则匹配失败，尝试使用原来的匹配方式
                const oldMatch = fileName.match(/^([A-Za-z0-9_]+)_/);
                if (oldMatch && oldMatch[1]) {
                  filePrefix = oldMatch[1];
                  console.log('使用备用方式提取的前缀:', filePrefix);
                } else {
                  console.warn('无法从文件名提取前缀，尝试直接匹配:', fileName);
                }
              }
              
              // 查找匹配的表头列表，确保前缀不以下划线结尾
              const cleanPrefix = filePrefix.replace(/_+$/, '');
              const tableHeaderListName = `${cleanPrefix}_TABLE_HEAR_LIST`;
              console.log('尝试匹配的表头列表名称:', tableHeaderListName);
              console.log('当前可用的表头列表:', Object.keys(this.tableHeaderLists));
              
              matchedHeaders = this.tableHeaderLists[tableHeaderListName] || [];
              console.log(`查找表头: ${tableHeaderListName}, 找到: ${matchedHeaders.length}列`);
              
              // 如果没有找到匹配的表头，尝试遍历所有表头列表进行模糊匹配
              if (matchedHeaders.length === 0) {
                console.log('尝试模糊匹配表头...');
                for (const [listName, headers] of Object.entries(this.tableHeaderLists)) {
                  // 使用清理后的前缀进行模糊匹配
                  if (listName.includes(cleanPrefix) || listName.includes(fileName.split('_')[0])) {
                    matchedHeaders = headers;
                    console.log(`模糊匹配成功: ${listName}, 表头数量: ${matchedHeaders.length}`);
                    break;
                  }
                }
                
                if (matchedHeaders.length === 0) {
                  console.warn(`未找到匹配的表头! 请确认Excel中是否包含与${filePrefix}相关的表头定义`);
                }
              }

              lines.forEach(line => {
                if (line.trim()) {
                  const fields = line.split('@!@');
                  const row = {};
                  fields.forEach((field, index) => {
                    // 使用匹配的表头或默认列名
                    const header = matchedHeaders[index] || `列${index + 1}`;
                    row[header] = field;
                  });
                  data.push(row);
                }
              });

              // 为每行数据添加索引属性
              const csvData = data.map((row, index) => {
                const rowObj = {...row};
                rowObj._index = index;
                return rowObj;
              });

              // 设置文件表头
              let fileHeaders = [];
              if (matchedHeaders.length > 0) {
                fileHeaders = matchedHeaders;
              } else {
                // 如果没有匹配的表头，则使用第一行数据的键作为表头
                if (data.length > 0) {
                  fileHeaders = Object.keys(data[0]);
                }
              }

              // 创建新文件数据对象
              const fileData = {
                name: file.name,
                csvData: csvData,
                originalData: JSON.parse(JSON.stringify(csvData)),
                headers: fileHeaders
              };

              // 添加到文件数据数组
              this.filesData.push(fileData);
              // 设置为当前活动文件
              this.activeFileIndex = this.filesData.length - 1;

              this.loading = false;
              this.$message.success(`DAT文件解析成功: ${file.name}，共 ${csvData.length} 行数据，${fileHeaders.length} 列`);
              // 强制更新视图
              this.$forceUpdate();
            } catch (error) {
              console.error('解析DAT文件出错:', error);
              this.$message.error('解析DAT文件出错: ' + error.message);
              this.loading = false;
            }
          };
          reader.readAsArrayBuffer(file.raw);
        } else {
          // 使用PapaParse解析CSV或无后缀名文件
          Papa.parse(file.raw, {
          header: true, // 将第一行视为表头
          skipEmptyLines: true, // 跳过空行
          encoding: 'utf-8', // 使用UTF-8编码
          complete: (results) => {
            console.log('解析完成，结果:', results);

            // 检查解析结果是否为空
            if (!results.data || results.data.length === 0) {
              this.loading = false;
              this.$message.warning('文件为空或格式不正确');
              return;
            }

            // 存储原始数据
            const originalData = JSON.parse(JSON.stringify(results.data));
            // 为每行数据添加索引属性
            const csvData = results.data.map((row, index) => {
              const rowObj = {...row};
              rowObj._index = index;
              return rowObj;
            });

            // 设置表头信息
            const headers = results.meta.fields || [];

            // 创建新文件数据对象
            const fileData = {
              name: file.name,
              csvData: csvData,
              originalData: originalData,
              headers: headers
            };

            // 添加到文件数据数组
            this.filesData.push(fileData);
            // 设置为当前活动文件
            this.activeFileIndex = this.filesData.length - 1;

            this.loading = false;
            this.$message.success(`文件解析成功: ${file.name}，共 ${csvData.length} 行数据，${headers.length} 列`);
            // 强制更新视图
            this.$forceUpdate();
          },
          error: (error) => {
            console.error('解析CSV文件出错:', error);
            this.$message.error('解析CSV文件出错: ' + error.message);
            this.loading = false;
          }
        });
      }
      },

      
      /**
       * 读取Excel文件内容
       */
      readExcelFile(file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          try {
            const data = new Uint8Array(e.target.result);
            const workbook = XLSX.read(data, { type: 'array' });
            this.excelHeaders = {}; // 存储每个DAT文件类型对应的表头
            this.tableHeaderLists = {}; // 存储以TABLE_HEAR_LIST格式命名的表头

            // 从第4个页签开始处理（索引为3），直到第12个页签（索引为11），处理8种文件类型
              for (let i = 3; i < 12 && i < workbook.SheetNames.length; i++) {
              const sheetName = workbook.SheetNames[i];
              const worksheet = workbook.Sheets[sheetName];

              // 获取第三行第四列的值（D3单元格）
              const datFilePattern = worksheet['D3']?.v || '';
              if (!datFilePattern) continue;

              // 获取第三行第五列的值（E3单元格）
              const fullFileType = worksheet['E3']?.v || '';
              console.log(`从页签${sheetName}的E3单元格提取的完整文件类型:`, fullFileType);
              if (!fullFileType) {
                console.warn(`页签${sheetName}的E3单元格为空，跳过此页签`);
                continue;
              }
              
              // 提取文件类型前缀（如JD_CUS, JD_PLAN）
              // 统一从页签名称中提取关键字并映射为对应的文件类型前缀
              let fileTypePrefix = '';
              
              if (sheetName.includes('客户信息')) {
                fileTypePrefix = 'JD_CUS';
              } else if (sheetName.includes('授信额度')) {
                fileTypePrefix = 'JD_CUSCREDIT';
              } else if (sheetName.includes('调额')) {
                fileTypePrefix = 'JD_QUOTAADJUST';
              } else if (sheetName.includes('贷款还款计划')) {
                fileTypePrefix = 'JD_PLAN';
              } else if (sheetName.includes('贷款借据')) {
                fileTypePrefix = 'JD_LOAN';
              } else if (sheetName.includes('贷款还款明细')) {
                fileTypePrefix = 'JD_FLOW';
              } else if (sheetName.includes('还款详情表')) {
                fileTypePrefix = 'JD_REPAYMENTFLOW';
              } else if (sheetName.includes('用户信息变更')) {
                fileTypePrefix = 'JD_CUSCHANGE';
              } else {
                console.warn(`无法从页签名称${sheetName}提取关键字，跳过此页签`);
                continue;
              }
              console.log(`从页签名称${sheetName}提取的文件类型前缀:`, fileTypePrefix);
              console.log(`提取的文件类型前缀:`, fileTypePrefix);

              // 提取DAT文件名前缀（如"JD_CUS_"）
              const fileTypeKey = datFilePattern.split('数据日期')[0].trim();
              if (!fileTypeKey) continue;

              // 获取表头行
              const headers = [];
              let rowIndex = 7;
              
              // 检查第7行C列是否为'中文名称'
              const firstCellAddress = `C${rowIndex}`;
              const firstCellValue = worksheet[firstCellAddress]?.v;
              
              // 如果第7行C列是'中文名称'，则从第8行开始读取正式表头
              if (firstCellValue === '中文名称') {
                rowIndex = 8;
                console.log(`页签${sheetName}的第7行C列是'中文名称'，从第8行开始读取表头`);
              } else {
                console.log(`页签${sheetName}的第7行C列不是'中文名称'，从第7行开始读取表头`);
              }
              
              // 开始读取表头
              while (true) {
                // 获取C列的值
                const cellAddress = `C${rowIndex}`;
                const cellValue = worksheet[cellAddress]?.v;
                if (!cellValue) break;

                headers.push(cellValue);
                rowIndex++;
              }

              if (headers.length > 0) {
                // 存储用于匹配DAT文件的表头
                this.excelHeaders[fileTypeKey] = headers;
                // 存储以TABLE_HEAR_LIST格式命名的表头
                // 确保fileTypePrefix不以下划线结尾，避免生成多余下划线
                const cleanPrefix = fileTypePrefix.replace(/_+$/, '');
                const listName = `${cleanPrefix}_TABLE_HEAR_LIST`;
                this.tableHeaderLists[listName] = headers;
                console.log(`已加载${fileTypeKey}的表头:`, headers);
                console.log(`已生成表头列表: ${listName}`);
              }
            }

            // 在控制台打印所有生成的表头列表
            console.log('生成的表头列表(tableHeaderLists):', this.tableHeaderLists);
            console.log('Excel文档解析成功，已加载表头信息，可在控制台查看详细表头数据');
            this.loading = false;
            this.$message.success('Excel文档解析成功，已加载表头信息，请在控制台查看详细表头数据');
          } catch (error) {
            this.loading = false;
            this.$message.error('Excel文档解析失败: ' + error.message);
            console.error('解析Excel失败:', error);
          }
        };
        reader.onerror = () => {
          this.loading = false;
          this.$message.error('读取Excel文件失败');
        };
        reader.readAsArrayBuffer(file.raw);
      },

      // 切换活动文件
      switchFile(index) {
        this.activeFileIndex = index;
        this.$message.info(`已切换到文件: ${this.filesData[index].name}`);
      },

      // 删除文件
      deleteFile(index) {
        if (index === this.activeFileIndex) {
          this.activeFileIndex = -1;
        } else if (index < this.activeFileIndex) {
          this.activeFileIndex--;
        }
        this.filesData.splice(index, 1);
        this.$message.success(`已删除文件`);
      },

      /**
       * 更新表格单元格数据
       * @param {number} rowIndex - 行索引
       * @param {string} colIndex - 列索引（字符串形式）
       * @param {string} value - 新的单元格值
       */
      updateCell(rowIndex, colIndex, value) {
        // 确保索引有效
        if (this.currentFileData && rowIndex >= 0 && rowIndex < this.csvData.length) {
          this.csvData[rowIndex][colIndex] = value;
        }
      },

      /**
       * 下载修改后的文件
       */
      downloadCSV() {
        if (!this.currentFileData) {
          this.$message.warning('请先选择一个文件');
          return;
        }

        // 获取文件名和扩展名
        const fileName = this.currentFileData.name;
        const lastDotIndex = fileName.lastIndexOf('.');
        const hasExtension = lastDotIndex !== -1;
        const extension = hasExtension ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';
        
        // 根据扩展名设置MIME类型
        let mimeType = 'application/octet-stream'; // 默认二进制流
        if (hasExtension && extension === 'csv') {
          mimeType = 'text/csv;charset=utf-8;';
        } else if (hasExtension && extension === 'dat') {
          mimeType = 'text/plain;charset=gbk;';
        }

        // 准备下载的数据，移除索引属性
        const dataToExport = this.csvData.map(row => {
          const { _index, ...rest } = row;
          return rest;
        });

        let blob;

        if (hasExtension && extension === 'dat') {
          // DAT文件：保持无表头，使用@!@分隔
          // 按表头顺序排列字段值
          const rows = dataToExport.map(row => {
            return this.headers.map(header => row[header] || '').join('@!@');
          });
          // 构建DAT内容
          const datContent = rows.join('\n');
          // DAT文件使用GBK编码
          // 使用Blob的charset参数处理GBK编码
          blob = new Blob([datContent], { type: mimeType });
        } else {
          // 其他文件格式（如CSV）：保持原有逻辑
          // 转换对象回数组格式并按列索引排序
          const formattedData = dataToExport.map(row => {
            const rowArray = [];
            Object.keys(row).sort((a, b) => parseInt(a) - parseInt(b)).forEach(key => {
              rowArray.push(row[key]);
            });
            return rowArray;
          });

          // 在数据前面添加表头行
          const headersRow = [...this.headers];
          formattedData.unshift(headersRow);

          // 配置Papa.unparse包含表头
          const csv = Papa.unparse(formattedData, { header: true });
          // 添加BOM以确保Windows系统能正确识别UTF-8编码
          const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
          blob = new Blob([bom, csv], { type: mimeType });
        }

        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url); // 释放URL对象

        this.$message.success(`文件 ${fileName} 下载成功`);
      },

      /**
       * 重置数据为原始状态
       */
      resetData() {
        if (!this.currentFileData) {
          this.$message.warning('请先选择一个文件');
          return;
        }

        // 重置数据
        this.currentFileData.csvData = JSON.parse(JSON.stringify(this.currentFileData.originalData)).map((row, index) => {
          const rowObj = {...row};
          rowObj._index = index;
          return rowObj;
        });
        this.$message.info(`文件 ${this.currentFileData.name} 数据已重置`);
      },

      /**
       * 根据列名查找列索引（考虑空格和大小写）
       * @param {string} columnName - 列名
       * @returns {number} 列索引，-1表示未找到
       */
      getColumnIndex(columnName) {
        if (!this.headers || this.headers.length === 0) return -1;
        return this.headers.findIndex(header =>
                header.trim().toLowerCase() === columnName.trim().toLowerCase()
        );
      },

      /**
       * 解析替换规则字符串
       * @returns {Object} 解析后的替换规则对象
       */
      parseReplaceRules() {
        const rules = {};
        if (!this.replaceRulesStr.trim()) return rules;

        try {
          console.log('替换规则字符串:', this.replaceRulesStr);
          // 按逗号分隔规则
          const ruleParts = this.replaceRulesStr.split(',');
          ruleParts.forEach(part => {
            // 按冒号分隔键值对
            const [key, value] = part.split(':');
            if (key && value !== undefined) {
              const trimmedKey = key.trim();
              rules[trimmedKey] = value.trim();
              console.log('解析到规则:', trimmedKey, '->', rules[trimmedKey]);
            } else {
              console.log('无效的规则部分:', part);
            }
          });
          console.log('解析后的规则对象:', rules);
        } catch (e) {
          this.$message.error('替换规则格式不正确，请使用 name:值,date:值 格式');
          console.error('解析替换规则出错:', e);
        }

        return rules;
      },

      /**
       * 检查替换规则是否有效（所有列名都存在）
       * @param {Object} rules - 替换规则
       * @returns {boolean} 是否有效
       */
      validateRules(rules) {
        let isValid = true;
        const invalidColumns = [];

        Object.keys(rules).forEach(columnName => {
          const index = this.getColumnIndex(columnName);
          if (index === -1) {
            invalidColumns.push(columnName);
            isValid = false;
          }
        });

        if (!isValid) {
          this.$message.warning(`以下列名在当前文件中不存在: ${invalidColumns.join(', ')}`);
          console.log(`无效列名: ${invalidColumns.join(', ')}`);
        }

        return isValid;
      },

      /**
       * 批量替换当前文件中的值
       */
      batchReplace() {
        if (!this.currentFileData) {
          this.$message.warning('请先选择一个文件');
          return;
        }

        const rules = this.parseReplaceRules();
        if (Object.keys(rules).length === 0) {
          this.$message.warning('请输入有效的替换规则，格式: name:王五,date:20250819');
          return;
        }

        // 验证规则中的列名是否存在
        if (!this.validateRules(rules)) {
          return;
        }

        let replaceCount = 0;
        console.log('当前文件列名(原始数组):', JSON.stringify(this.headers));
        // 添加详细调试：检查每个header的实际值和长度
        this.headers.forEach((header, index) => {
          console.log(`表头[${index}]: ${header}, 长度: ${header.length}`);
        });

        // 遍历当前文件的所有行
        this.csvData.forEach((row, rowIndex) => {
          // 打印第一行数据结构，帮助调试
          if (rowIndex === 0) {
            console.log('第一行数据结构:', row);
            console.log('第一行包含的列:', Object.keys(row).join(','));
          }

          // 遍历所有替换规则
          Object.entries(rules).forEach(([columnName, replaceValue]) => {
            // 获取列索引（考虑空格和大小写）
            const columnIndex = this.getColumnIndex(columnName);
            const actualColumnName = this.headers[columnIndex];

            // 特别针对type字段的调试
            if (columnName.toLowerCase() === 'type') {
              console.log(`处理type字段替换，当前行:${rowIndex+1}`);
              console.log(`列索引: ${columnIndex}, 实际列名: ${actualColumnName}`);
            }

            // 检查列是否存在
            if (columnIndex !== -1 && row.hasOwnProperty(actualColumnName)) {
              // 替换值
              const oldValue = row[actualColumnName];
              row[actualColumnName] = replaceValue;
              replaceCount++;
              console.log(`第${rowIndex+1}行: 将${actualColumnName}从"${oldValue}"替换为"${replaceValue}"`);
            } else {
              console.log(`警告: 行${rowIndex+1}中不存在列${columnName}`);
              // 打印行中可用的列，帮助用户确认
              console.log(`行${rowIndex+1}可用列:`, Object.keys(row).join(','));
            }
          });
        });

        this.$message.success(`当前文件替换完成，共替换 ${replaceCount} 处`);
      },

      /**
       * 批量替换所有文件中的值
       */
      batchReplaceAll() {
        if (this.filesData.length === 0) {
          this.$message.warning('没有文件可替换');
          return;
        }

        const rules = this.parseReplaceRules();
        if (Object.keys(rules).length === 0) {
          this.$message.warning('请输入有效的替换规则，格式: name:王五,date:20250819');
          return;
        }

        let totalReplaceCount = 0;
        const filesWithChanges = [];

        // 遍历所有文件
        this.filesData.forEach((fileData, fileIndex) => {
          // 保存当前文件的表头，以便validateRules使用
          const originalHeaders = this.headers;
          this.currentFileData = fileData;

          // 验证当前文件是否包含所有规则列
          if (this.validateRules(rules)) {
            let fileReplaceCount = 0;

            // 遍历当前文件的所有行
            fileData.csvData.forEach(row => {
              // 遍历所有替换规则
              Object.entries(rules).forEach(([columnName, replaceValue]) => {
                // 获取列索引（考虑空格和大小写）
                const columnIndex = this.getColumnIndex(columnName);
                const actualColumnName = this.headers[columnIndex];

                // 检查列是否存在
                if (columnIndex !== -1 && row.hasOwnProperty(actualColumnName)) {
                  // 替换值
                  row[actualColumnName] = replaceValue;
                  fileReplaceCount++;
                }
              });
            });

            if (fileReplaceCount > 0) {
              filesWithChanges.push({ name: fileData.name, count: fileReplaceCount });
              totalReplaceCount += fileReplaceCount;
            }
          }

          // 恢复原始表头
          this.currentFileData = originalHeaders;
        });

        if (filesWithChanges.length > 0) {
          let message = `所有文件替换完成，共替换 ${totalReplaceCount} 处`;
          filesWithChanges.forEach(file => {
            message += `\n- ${file.name}: ${file.count} 处`;
          });
          this.$message.success(message);
        } else {
          this.$message.info('没有文件被修改');
        }
      },


      /**
       * 下载所有文件
       */
      downloadAllCSV() {
        if (this.filesData.length === 0) {
          this.$message.warning('没有文件可下载');
          return;
        }

        this.$message.info('开始下载所有文件...');

        // 为每个文件创建下载链接
        this.filesData.forEach(fileData => {
          // 获取文件名和扩展名
          const fileName = fileData.name;
          const lastDotIndex = fileName.lastIndexOf('.');
          const hasExtension = lastDotIndex !== -1;
          const extension = hasExtension ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';

          // 根据扩展名设置MIME类型
          let mimeType = 'application/octet-stream'; // 默认二进制流
          if (hasExtension && extension === 'csv') {
            mimeType = 'text/csv;charset=utf-8;';
          } else if (hasExtension && extension === 'dat') {
            mimeType = 'text/plain;charset=gbk;';
          }

          // 准备下载的数据，移除索引属性
          const dataToExport = fileData.csvData.map(row => {
            const { _index, ...rest } = row;
            return rest;
          });

          let blob;

          if (hasExtension && extension === 'dat') {
            // DAT文件：保持无表头，使用@!@分隔
            // 按表头顺序排列字段值
            const rows = dataToExport.map(row => {
              return fileData.headers.map(header => row[header] || '').join('@!@');
            });
            // 构建DAT内容
            const datContent = rows.join('\n');
            // DAT文件使用GBK编码
            // 使用Blob的charset参数处理GBK编码
            blob = new Blob([datContent], { type: mimeType });
          } else {
            // 其他文件格式（如CSV）：保持原有逻辑
            // 转换对象回数组格式并按列索引排序
            const formattedData = dataToExport.map(row => {
              const rowArray = [];
              Object.keys(row).sort((a, b) => parseInt(a) - parseInt(b)).forEach(key => {
                rowArray.push(row[key]);
              });
              return rowArray;
            });

            // 在数据前面添加表头行
            const headersRow = [...fileData.headers];
            formattedData.unshift(headersRow);

            // 配置Papa.unparse包含表头
            const csv = Papa.unparse(formattedData, { header: true });
            // 添加BOM以确保Windows系统能正确识别UTF-8编码
            const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
            blob = new Blob([bom, csv], { type: mimeType });
          }

          const url = URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = url;
          link.setAttribute('download', fileName);
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          URL.revokeObjectURL(url); // 释放URL对象
        });

        this.$message.success(`已成功下载 ${this.filesData.length} 个文件`);
      }
    }
  });
</script>
</body>
</html>
